home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / go32 / fs / serial.c < prev    next >
C/C++ Source or Header  |  1995-03-23  |  17KB  |  639 lines

  1. #include <stdio.h>
  2. #include <std.h>
  3. #include <sys/types.h>
  4. #include <dos.h>
  5. #include <pc.h>
  6. #include <go32.h>
  7. #include <dpmi.h>
  8. #define far
  9. #include "ed.h"
  10. #include "unassmbl.h"
  11. #include "serial.h"
  12. #include "syms.h"
  13.  
  14. #define MaxPort 4
  15.  
  16. static int UartBase[MaxPort] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
  17. static int IntNums [MaxPort] = { 0x0C, 0x0B, 0x0C, 0x0B };
  18. static int I8259Levels[MaxPort] = {4, 3, 4, 3};
  19. static int ComInstalled = 0;
  20.  
  21. static unsigned int UartData;             /*Data register*/
  22. static unsigned int UartIer ;             /*Interrupt enable register*/
  23. static unsigned int UartIir ;             /*Interrupt identification register*/
  24. static unsigned int UartLcr ;             /*Line control register*/
  25. static unsigned int UartMcr ;             /*Modem control register*/
  26. static unsigned int UartLsr ;             /*Line status register*/
  27. static unsigned int UartMsr ;             /*Modem status register*/
  28. static unsigned int UartSpr ;             /*Scratch pad register */
  29.  
  30. static unsigned char OldIer, OldMcr;
  31. static unsigned int OldI8259Mask;
  32.  
  33. static _go32_dpmi_seginfo   rm_old_irq;
  34. static _go32_dpmi_registers rm_regs;
  35. static _go32_dpmi_seginfo   rm_si;
  36. static _go32_dpmi_seginfo   pm_old_irq;
  37. static _go32_dpmi_seginfo   pm_si;
  38.  
  39. static _go32_dpmi_seginfo   rm_old_irq_1c;
  40. static _go32_dpmi_registers rm_regs_1c;
  41. static _go32_dpmi_seginfo   rm_si_1c;
  42.  
  43. static unsigned int I8259Bit;
  44. static unsigned int IntNum;
  45.  
  46. typedef char *comnames;
  47. static comnames DOSDEV[5] = { "CON", "COM1", "COM2", "COM3", "COM4" };
  48.  
  49. volatile unsigned long eip, ebp, esp, eflag;
  50.  
  51. #define RxQueueSize 4096
  52. #define TxQueueSize 4096
  53. static char RxQueue[RxQueueSize];
  54. static char TxQueue[TxQueueSize];
  55. static unsigned int RxIn, RxOut, TxIn, TxOut; /*Index of next character*/
  56. static unsigned int RxChars, TxChars;         /*Number of chars in queue*/
  57. static int curr_port     = 0;
  58. static int int_1c_counts = 0;
  59. static word32 caller_address = 0;
  60. static word32 caller_value   = 0;
  61. extern int is_in_running_mode;
  62.  
  63. /* ---------------------------------------------------------------------- */
  64. static char *stack;
  65. static word32 my_esp, my_ebp, my_ss, old_esp, old_ebp, old_ss;
  66. static switch_stack = 0;
  67. /* ---------------------------------------------------------------------- */
  68. static void
  69. refresh_uart (void)
  70. { /* outportb (UartIer, 0);                    */
  71.   asm ("xor %al, %al           \n\
  72.     mov _UartIer, %dx      \n\
  73.     out %al, %dx");
  74.   /* outportb (0x21, OldI8259Mask | I8259Bit); */
  75.   asm ("mov $0x21, %dx         \n\
  76.     mov _OldI8259Mask, %al \n\
  77.     or  _I8259Bit, %al     \n\
  78.     out %al, %dx");   
  79.   /* outportb (UartLcr, 3);                    */
  80.   asm ("mov $0x03, %al         \n\
  81.     mov _UartLcr, %dx      \n\
  82.     out %al, %dx");  
  83.   /* outportb (UartMcr, 0x0a | (OldMcr & 1));  */
  84.   asm ("mov _UartMcr, %dx      \n\
  85.     mov _OldMcr, %al       \n\
  86.     and $0x01, %al         \n\
  87.     or  $0x0a, %al         \n\
  88.     out %al, %dx");
  89.   /* outportb (UartIer, inportb (UartIer) | 1);*/
  90.   asm ("mov _UartIer, %dx      \n\
  91.     in  %dx, %al           \n\
  92.     or  $0x01, %al         \n\
  93.     out %al, %dx");
  94.   /*outportb (0x21, inportb (0x21) & ~I8259Bit);*/
  95.   asm ("mov $0x21, %dx         \n\
  96.     mov _I8259Bit, %cl     \n\
  97.     not %cl                \n\
  98.     in  %dx, %al           \n\
  99.     and %cl, %al           \n\
  100.     out %al, %dx");   
  101.   TxChars = 0;
  102.   TxIn    = 0;
  103.   TxOut   = 0;
  104. }
  105. /* ---------------------------------------------------------------------- */
  106. static void
  107. rm_isr_1c (void)
  108. { if (is_in_running_mode)
  109.   { if (++int_1c_counts >= 18)
  110.     { refresh_uart ();
  111.       int_1c_counts = 0;
  112.     }
  113.   }
  114. }
  115. /* ---------------------------------------------------------------------- */
  116. static int ch, Iir, ctrl_c_hit;
  117. /* ---------------------------------------------------------------------- */
  118. static void
  119. ComInterruptDriver (void)
  120. {
  121.   asm("cli");
  122. /*  if (switch_stack)
  123.     asm("movl %esp, %eax     \n\
  124.      movl %eax, _old_esp \n\
  125.      movl %ebp, %eax     \n\
  126.      movl %eax, _old_ebp \n\
  127.      movw %ss, %ax       \n\
  128.      movw %ax, _old_ss   \n\
  129.      movl _my_esp, %eax  \n\
  130.      movl %eax, %esp     \n\
  131.      movl _my_ebp, %eax  \n\
  132.      movl %eax, %ebp     \n\
  133.      movw _my_ss, %ax    \n\
  134.      movw %ax, %ss       \n\
  135.     ");  */
  136.   Iir = inportb (UartIir);
  137.   while (!(Iir % 2))
  138.   {
  139.     ch = 0;
  140.     switch (Iir >> 1)
  141.     {
  142.       case 2:
  143.     ch = inportb (UartData);  /* realmode: cannot get accurate eip. */
  144.     if (ch == 3)
  145.        ctrl_c_hit = 1;
  146.     if (RxChars < RxQueueSize)
  147.     {
  148.       RxQueue [RxIn] = ch;
  149.       RxIn++;
  150.       if (RxIn >= RxQueueSize)
  151.         RxIn = 0;
  152.       RxChars++;
  153.     }
  154.     break;
  155.       case 1:
  156.     if (TxChars <= 0)
  157.       outportb (UartIer, inportb (UartIer) & ~2);
  158.     else if ((inportb (UartLsr) >> 5) %2)
  159.       {
  160.         outportb (UartData, TxQueue [TxOut]);
  161.         TxOut++;
  162.         if (TxOut >= TxQueueSize)
  163.           TxOut = 0;
  164.         TxChars--;
  165.       }
  166.     break;
  167.       case 0:
  168.     (void) inportb (UartMsr);
  169.     break;
  170.       case 3:
  171.     ch = inportb (UartLsr);
  172.     break;
  173.     }
  174.     Iir = inportb (UartIir);
  175.   }
  176.   outportb (0x20, 0x20);
  177. /*  if (switch_stack)
  178.     asm("movl %esp, %eax     \n\
  179.      movl %eax, _my_esp  \n\
  180.      movl %ebp, %eax     \n\
  181.      movl %eax, _my_ebp  \n\
  182.      movl _old_esp, %eax \n\
  183.      movl %eax, %esp     \n\
  184.      movl _old_ebp, %eax \n\
  185.      movl %eax, %ebp     \n\
  186.      movw _old_ss, %ax   \n\
  187.      movw %ax, %ss       \n\
  188.      leave               \n\
  189.      ret                 \n\
  190.     ");  */
  191. }
  192. /* ---------------------------------------------------------------------- */
  193. static void
  194. pmComInterruptDriver (_go32_dpmi_registers r)
  195. {
  196.   asm("cli                 \n\
  197.        push %eax           \n\
  198.        push %ebx           \n\
  199.        push %ecx           \n\
  200.        push %edx           \n\
  201.        push %esi           \n\
  202.        push %edi           \n\
  203.       ");
  204.   asm("push %ds            \n\
  205.        movw $0x107, %ax    \n\
  206.        movw %ax, %ds       \n\
  207.       ");
  208. /*  if (switch_stack)
  209.     asm("movl %esp, %eax     \n\
  210.      movl %eax, _old_esp \n\
  211.      movl %ebp, %eax     \n\
  212.      movl %eax, _old_ebp \n\
  213.      movw %ss, %ax       \n\
  214.      movw %ax, _old_ss   \n\
  215.      movl _my_esp, %eax  \n\
  216.      movl %eax, %esp     \n\
  217.      movl _my_ebp, %eax  \n\
  218.      movl %eax, %ebp     \n\
  219.      movw _my_ss, %ax    \n\
  220.      movw %ax, %ss       \n\
  221.     ");  */
  222.  
  223.   Iir = inportb (UartIir);
  224.  
  225.   while (!(Iir % 2))
  226.   {
  227.     switch (Iir >> 1)
  228.     {
  229.       case 2:
  230.     ch = inportb (UartData);
  231.     if (ch == 3)
  232.       ctrl_c_hit = 1;
  233.     if (RxChars < RxQueueSize)
  234.     {
  235.       RxQueue [RxIn] = ch;
  236.       RxIn++;
  237.       if (RxIn >= RxQueueSize)
  238.         RxIn = 0;
  239.       RxChars++;
  240.     }
  241.     break;
  242.       case 1:
  243.     if (TxChars <= 0)
  244.       outportb (UartIer, inportb (UartIer) & ~2);
  245.     else if ((inportb (UartLsr) >> 5) %2)
  246.       {
  247.         outportb (UartData, TxQueue [TxOut]);
  248.         TxOut++;
  249.         if (TxOut >= TxQueueSize)
  250.           TxOut = 0;
  251.         TxChars--;
  252.       }
  253.     break;
  254.       case 0:
  255.     (void) inportb (UartMsr);
  256.     break;
  257.       case 3:
  258.     ch = inportb (UartLsr);
  259.     break;
  260.     }
  261.     Iir = inportb (UartIir);
  262.   }
  263.   if (ctrl_c_hit)
  264.   { ctrl_c_hit = 0;
  265.     if (is_in_running_mode && !switch_stack)
  266.     { asm("movl %ebp,%eax");
  267.       asm("add  $0x0c,%eax");
  268.       asm("movl (%eax),%edx");
  269.       asm("movl %edx,_eflag");
  270.       eflag |= 0x0100;
  271.       asm("movl %ebp,%eax");
  272.       asm("add  $0x0c,%eax");
  273.       asm("movl _eflag,%edx");
  274.       asm("movl %edx,(%eax)");
  275.     }
  276.   }
  277.   asm("mov  $0x20,%al");
  278.   asm("out  %al,$0x20");
  279.  
  280. /*  if (switch_stack)
  281.     asm("movl %esp, %eax     \n\
  282.      movl %eax, _my_esp  \n\
  283.      movl %ebp, %eax     \n\
  284.      movl %eax, _my_ebp  \n\
  285.      movl _old_esp, %eax \n\
  286.      movl %eax, %esp     \n\
  287.      movl _old_ebp, %eax \n\
  288.      movl %eax, %ebp     \n\
  289.      movw _old_ss, %ax   \n\
  290.      movw %ax, %ss       \n\
  291.     ");  */
  292.   asm("pop  %ds");
  293.   asm("pop  %edi       \n\
  294.        pop  %esi           \n\
  295.        pop  %edx           \n\
  296.        pop  %ecx           \n\
  297.        pop  %ebx           \n\
  298.        pop  %eax           \n\
  299.        leave               \n\
  300.        iret                \n\
  301.       ");
  302. }
  303. /* ---------------------------------------------------------------------- */
  304. static void
  305. com_install_refresh_int (void)
  306. { int ret;
  307.   word32 value;
  308.  
  309.   value = (word32) refresh_uart;
  310.   caller_address = syms_name2val ("Dosx_call_debugger_every_sec");
  311.   if (undefined_symbol)
  312.   { undefined_symbol = 0;
  313.     caller_address = 0;
  314.   }
  315.   if (caller_address)
  316.   { read_child  (caller_address, &caller_value, sizeof (word32));
  317.     write_child (caller_address, &value,  sizeof (word32));
  318.   } else
  319.   { rm_si_1c.pm_offset = (int) rm_isr_1c;
  320.     ret = _go32_dpmi_allocate_real_mode_callback_iret(&rm_si_1c, &rm_regs_1c);
  321.     disable();
  322.     _go32_dpmi_get_real_mode_interrupt_vector(0x1c, &rm_old_irq_1c);
  323.     _go32_dpmi_set_real_mode_interrupt_vector(0x1c, &rm_si_1c);
  324.     enable();
  325.   }
  326. }
  327. /* ---------------------------------------------------------------------- */
  328. static void
  329. com_remove_refresh_int (void)
  330. { if (caller_address)
  331.   { write_child (caller_address, &caller_value,  sizeof (word32));
  332.   } else
  333.   { disable ();
  334.     _go32_dpmi_set_real_mode_interrupt_vector(0x1c, &rm_old_irq_1c);
  335.     _go32_dpmi_free_real_mode_callback(&rm_si_1c);
  336.     enable ();
  337.   }
  338. }
  339. /* ---------------------------------------------------------------------- */
  340. static int
  341. com_install_rm_irq (int vect_num)
  342. { int ret;
  343.  
  344.   rm_si.pm_offset = (int) ComInterruptDriver;
  345.   ret = _go32_dpmi_allocate_real_mode_callback_iret(&rm_si, &rm_regs);
  346.   if (ret)
  347.     return 0;
  348.  
  349.   disable();
  350.   _go32_dpmi_get_real_mode_interrupt_vector(vect_num, &rm_old_irq);
  351.   _go32_dpmi_set_real_mode_interrupt_vector(vect_num, &rm_si);
  352.   enable();
  353.  
  354.   com_install_refresh_int ();
  355.   
  356.   return 1;
  357. }
  358. /* ---------------------------------------------------------------------- */
  359. static void
  360. com_remove_rm_irq (int vect_num)
  361. { com_remove_refresh_int ();
  362.   disable();
  363.   _go32_dpmi_set_real_mode_interrupt_vector(vect_num, &rm_old_irq);
  364.   _go32_dpmi_free_real_mode_callback(&rm_si);
  365.   enable();
  366. }
  367. /* ---------------------------------------------------------------------- */
  368. static void
  369. com_install_pm_irq (int vect_num)
  370. { disable();
  371.   _go32_dpmi_get_protected_mode_interrupt_vector(vect_num, &pm_old_irq);
  372.   pm_si.pm_offset = (int) pmComInterruptDriver;
  373.   pm_si.pm_selector = _go32_my_cs();
  374.   _go32_dpmi_set_protected_mode_interrupt_vector(vect_num, &pm_si);
  375.   enable();
  376. }
  377. /* ---------------------------------------------------------------------- */
  378. static void
  379. com_remove_pm_irq (int vect_num)
  380. { disable();
  381.   _go32_dpmi_set_protected_mode_interrupt_vector(vect_num, &pm_old_irq);
  382.   enable();
  383. }
  384. /* ---------------------------------------------------------------------- */
  385. static int
  386. install_irq (int vect_num)
  387. { if (_go32_info_block.run_mode == _GO32_RUN_MODE_DPMI)
  388.   { switch_stack = 1;
  389.     stack = (char *)1; /* malloc (0x4000); */
  390.     if (!stack)
  391.       return (0);
  392.     my_esp = (word32)stack + 0x4000 - 8;
  393.     my_ebp = my_esp;
  394.     old_esp = 0;
  395.     old_ebp = 0;
  396.     old_ss  = 0;
  397.   }
  398.   my_ss  = _go32_my_ds ();
  399.   write_child ((word32)pmComInterruptDriver + 0x0d, &my_ss, 2);
  400.  
  401.   if (!com_install_rm_irq(vect_num))
  402.     return 0;
  403.   com_install_pm_irq(vect_num);
  404.   return 1;
  405. }
  406. /* ---------------------------------------------------------------------- */
  407. static void
  408. remove_irq (int vect_num)
  409. { com_remove_rm_irq(vect_num);
  410.   com_remove_pm_irq(vect_num);
  411. }
  412. /* ---------------------------------------------------------------------- */
  413. void
  414. com_flush_rx (void)
  415. { disable();
  416.   RxChars = 0;
  417.   RxIn    = 0;
  418.   RxOut   = 0;
  419.   enable();
  420. }
  421. /* ---------------------------------------------------------------------- */
  422. void
  423. com_flush_tx (void)
  424. { disable();
  425.   TxChars = 0;
  426.   TxIn    = 0;
  427.   TxOut   = 0;
  428.   enable();
  429. }
  430. /* ---------------------------------------------------------------------- */
  431. int
  432. com_carrier (void)
  433. { return ComInstalled && ((inportw (UartMsr) >> 7) %2);
  434. }
  435. /* ---------------------------------------------------------------------- */
  436. int
  437. com_tx_ready (void)
  438. { return (TxChars < TxQueueSize);
  439. }
  440. /* ---------------------------------------------------------------------- */
  441. int
  442. com_tx_empty (void)
  443. { return (TxChars == 0);
  444. }
  445. /* ---------------------------------------------------------------------- */
  446. int
  447. com_rx_empty (void)
  448. { return (RxChars == 0);
  449. }
  450. /* ---------------------------------------------------------------------- */
  451. void
  452. com_lower_dtr (void)
  453. { if (ComInstalled)
  454.   { disable();
  455.     outportb (UartMcr, inportb (UartMcr) & ~1);
  456.     enable();
  457.   }
  458. }
  459. /* ---------------------------------------------------------------------- */
  460. void
  461. com_raise_dtr (void)
  462. { if (ComInstalled)
  463.   { disable();
  464.     outportb (UartMcr, inportb (UartMcr) | 1);
  465.     enable();
  466.   }
  467. }
  468. /* ---------------------------------------------------------------------- */
  469. void
  470. com_set_speed (unsigned int Speed)
  471. { int Divisor;
  472.   if (ComInstalled)
  473.   { if (Speed < 2)
  474.       Speed = 2;
  475.     Divisor = 115200L / Speed;
  476.     disable();
  477.     outportb (UartLcr, inportb (UartLcr) | 0x80);
  478.     outportw (UartData, Divisor);
  479.     outportb (UartLcr, inportb (UartLcr) & ~0x80);
  480.     enable();
  481.   }
  482. }
  483. /* ---------------------------------------------------------------------- */
  484. void
  485. com_set_parity (void)
  486. { int Lcr;
  487.   Lcr = 0x00 | 0x03;
  488.   disable();
  489.   outportb (UartLcr, (inportb (UartLcr) & 0x40) | Lcr);
  490.   enable();
  491. }
  492. /* ---------------------------------------------------------------------- */
  493. int
  494. com_install (int PortNum)
  495. { if (ComInstalled)
  496.     return 3;
  497.   if ((PortNum < 1) || (PortNum > MaxPort))
  498.     return 1;
  499.  
  500.   UartData = UartBase [PortNum - 1];
  501.   UartIer  = UartData + 1;
  502.   UartIir  = UartData + 2;
  503.   UartLcr  = UartData + 3;
  504.   UartMcr  = UartData + 4;
  505.   UartLsr  = UartData + 5;
  506.   UartMsr  = UartData + 6;
  507.   UartSpr  = UartData + 7;
  508.   IntNum   = IntNums [PortNum - 1];
  509.   I8259Bit = 1 << I8259Levels [PortNum - 1];
  510.  
  511.   OldIer   = inportb (UartIer);
  512.   outportb (UartIer, 0);
  513.   if (inportb (UartIer) != 0)
  514.     return 2;
  515.  
  516.   disable();
  517.   OldI8259Mask = inportb (0x21);
  518.   outportb (0x21, OldI8259Mask | I8259Bit);
  519.   enable();
  520.  
  521.   com_flush_tx();
  522.   com_flush_rx();
  523.  
  524.   if (!install_irq (IntNum))
  525.     return 4;
  526.   ComInstalled = 1;
  527.  
  528.   outportb (UartLcr, 3);
  529.  
  530.   disable();
  531.   OldMcr = inportb (UartMcr);
  532.   outportb (UartMcr, 0x0a | (OldMcr & 1));
  533.   enable();
  534.  
  535.   outportb (UartIer, 1);   
  536.  
  537.   disable();
  538.   outportb (0x21, inportb (0x21) & ~I8259Bit);
  539.   enable();  
  540.  
  541.   curr_port = PortNum;
  542.   return 0;
  543. }
  544. /* ---------------------------------------------------------------------- */
  545. static void
  546. redirect_init (int dev_num)
  547. { freopen (DOSDEV[dev_num], "w", stderr);
  548.   freopen (DOSDEV[dev_num], "r", stdin);
  549.   freopen (DOSDEV[dev_num], "w", stdout);
  550. }
  551. /* ---------------------------------------------------------------------- */
  552. static void
  553. redirect_done (void)
  554. { redirect_init (0);  
  555. }
  556. /* ---------------------------------------------------------------------- */
  557. int
  558. com_init (int port_num)
  559. { int i;
  560.  
  561.   i  = com_install (port_num);
  562.   if (i)
  563.     return i;
  564.   com_set_speed (9600);
  565.   com_set_parity();       
  566.   redirect_init (port_num);  
  567.   ComInstalled = 1;      
  568.   return 0;
  569. }
  570. /* ---------------------------------------------------------------------- */
  571. void
  572. com_done (void)
  573. { if (ComInstalled)
  574.   { ComInstalled = 0;      
  575.     outportb (UartMcr, OldMcr);
  576.     outportb (UartIer, OldIer);
  577.     disable();
  578.     outportb (0x21, ((inportb (0x21) & ~I8259Bit) | OldI8259Mask) & I8259Bit);
  579.     enable();
  580.     remove_irq (IntNum);   
  581.     redirect_done ();
  582.   }
  583. }
  584. /* ---------------------------------------------------------------------- */
  585. int
  586. com_rx (void)
  587. { int temp = 0;
  588.  
  589.   if (!RxChars)
  590.    return 0;
  591.   if (!ComInstalled)
  592.     return 0;
  593.   asm("cli");
  594.   temp = RxQueue[RxOut];
  595.   RxOut++;
  596.   if (RxOut >= RxQueueSize)
  597.     RxOut = 0;
  598.   RxChars--;
  599.   asm("sti");   
  600.   return temp;
  601. }
  602. /* ---------------------------------------------------------------------- */
  603. void
  604. com_tx (int ch)
  605. { if (ComInstalled)
  606.   { do {
  607.     } while (!com_tx_ready);
  608.     asm("cli");
  609.     TxQueue [TxIn] = ch;
  610.       TxIn++;
  611.     if (TxIn >= TxQueueSize)
  612.       TxIn = 0;
  613.     TxChars++;
  614.     outportb (UartIer, inportb (UartIer) | 2);
  615.     asm("sti");  
  616.   } 
  617. }
  618. /* ---------------------------------------------------------------------- */
  619. void
  620. com_txs (char *s)
  621. { if (ComInstalled)
  622.   { while (*s)
  623.     { do {
  624.       } while (TxChars >= TxQueueSize);
  625.       asm("cli");
  626.       do {
  627.     TxQueue [TxIn] = *s++;
  628.     TxIn++;
  629.     if (TxIn >= TxQueueSize)
  630.       TxIn = 0;
  631.     TxChars++;
  632.       } while ((TxChars < TxQueueSize) && (*s));
  633.       outportb (UartIer, inportb (UartIer) | 2);
  634.       asm("sti");  
  635.     }
  636.   }
  637. }
  638. /* ---------------------------------------------------------------------- */
  639.